"""
类和实例变量

参考文档: https://docs.python.org/zh-cn/3/tutorial/classes.html#class-and-instance-variables

实例变量是用于每个实例的唯一数据，而类变量用于类的所有实例共享的属性和方法
类比于C++的类静态属性

"""

def testClassAndInstanceVal():
    """类和实例变量"""

    # 定义一个Dog类
    class Dog:
        """Dog 类"""
        # kind属性是类变量，每个实例都可以共享
        kind = "田园犬"

        def __init__(self, name) -> None:
            # 定义实例变量name
            self.name = name
        
    fido = Dog('Fido')
    buddy = Dog('Buddy')

    # 查看每个实例的共享变量
    print("fido.kind is {0} and buddy.kind is {1}".format(fido.kind, buddy.kind))

    # 每个实例独有的属性
    print("fido.name is {0} and buddy.name is {1}".format(fido.name, buddy.name))


    # 正确的类设计应该使用实例变量而不是类变量
    # 所谓的实例变量就是每个实例的属性可以不一样，而不是所有实例都一样的变量
    # 共享数据如果涉及到可以修改的对象的时候，例如list和dict，可能会产生意想不到的错误

    class Cat:

        # tricks是一个类变量，每个实例变量都可以引用和修改
        tricks = []

        def __init__(self, name):
            self.name = name

        def addTrick(self, trick):
            self.tricks.append(trick)
    
    cat = Cat('Timi')
    fat = Cat('Hi')
    
    print("cat is {0} and tricks is {1}".format(cat.name, cat.tricks))
    print("fat is {0} and tricks is {1}".format(fat.name, fat.tricks))

    cat.addTrick("RollOver")
    fat.addTrick("PlayHead")

    # 这是个错误的设计，tricks里的内容每个实例对象都会共享，不单独所有
    print("cat is {0} and tricks is {1}".format(cat.name, cat.tricks))
    print("fat is {0} and tricks is {1}".format(fat.name, fat.tricks))

    # 修改之后的设计应该是这样的
    class CatFixed:

        # 构造函数里声明变量
        def __init__(self, name):
            self.name = name
            self.tricks = []

        def addTrick(self, trick):
            self.tricks.append(trick)
        
    catfixed = CatFixed('Timi')
    fatfiexd = CatFixed('Hi')
    
    print("catfixed is {0} and tricks is {1}".format(catfixed.name, catfixed.tricks))
    print("fatfixed is {0} and tricks is {1}".format(fatfiexd.name, fatfiexd.tricks))

    catfixed.addTrick("RollOver")
    fatfiexd.addTrick("PlayHead")

    # 这里的tricks就是每个实例单独所有的变量了
    print("catfixed is {0} and tricks is {1}".format(catfixed.name, catfixed.tricks))
    print("fatfixed is {0} and tricks is {1}".format(fatfiexd.name, fatfiexd.tricks))
        


testClassAndInstanceVal()